home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Freeware / Griffith 0.9.8 / griffith-0.9.8-win32.exe / {app} / lib / backup.py < prev    next >
Text File  |  2008-11-17  |  10KB  |  263 lines

  1. # -*- coding: UTF-8 -*-
  2.  
  3. __revision__ = '$Id: backup.py 1040 2008-11-15 21:13:49Z mikej06 $'
  4.  
  5. # Copyright (c) 2005-2008 Vasco Nunes, Piotr O┼╝arowski
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. # GNU Library General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  20.  
  21. # You may use and distribute this software under the terms of the
  22. # GNU General Public License, version 2 or later
  23.  
  24. import config, edit, gutils, sql
  25. import gtk
  26. import os.path
  27. import zipfile
  28.  
  29. def backup(self):
  30.     """perform a compressed griffith database/posters/preferences backup"""
  31.     filename = gutils.file_chooser(_("Save Griffith backup"), \
  32.         action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons= \
  33.         (gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK), \
  34.         name=self.config.get('name','griffith', section='database') + '_backup.zip')
  35.     if filename and filename[0]:
  36.         overwrite = None
  37.         zipfilename = filename[0].decode('utf-8')
  38.         if os.path.isfile(zipfilename):
  39.             response = gutils.question(self, \
  40.                 _("File exists. Do you want to overwrite it?"), \
  41.                 1, self.widgets['window'])
  42.             if response == -8:
  43.                 overwrite = True
  44.             else:
  45.                 overwrite = False
  46.  
  47.         if overwrite == True or overwrite is None:
  48.             try:
  49.                 if zipfile.zlib is not None:
  50.                     mzip = zipfile.ZipFile(zipfilename, 'w', zipfile.ZIP_DEFLATED)
  51.                 else:
  52.                     mzip = zipfile.ZipFile(zipfilename, 'w')
  53.             except:
  54.                 gutils.error(self, _("Error creating backup"), self.widgets['window'])
  55.                 return False
  56.             mzip.write(os.path.join(self.locations['home'],'griffith.cfg').encode('utf-8'))
  57.             if self.db.metadata.engine.name == 'sqlite':
  58.                 fileName = os.path.join(self.locations['home'], self.config.get('name','griffith', section='database') + '.db').encode('utf-8')
  59.                 mzip.write(fileName)
  60.             else:
  61.                 gutils.error(self, _("Backup function is available only for SQLite engine for now"), self.widgets['window'])
  62.                 return False
  63.                 from tempfile import mkdtemp
  64.                 from shutil import rmtree, move
  65.                 from sqlalchemy import BoundMetaData
  66.                 import copy
  67.                 # if backup_to_sqlite:
  68.                 tmp_dir = mkdtemp()
  69.                 tmp_config = copy.deepcopy(self.config)
  70.                 tmp_config._file = os.path.join(tmp_dir,'griffith.cfg')
  71.                 tmp_config.get('type', 'sqlite', section='database') == 'sqlite'
  72.                 tmp_config.set('file', section='database') == "griffith.db"
  73.                 tmp_config.save()
  74.  
  75. #                tmp_db = sql.GriffithSQL(tmp_config, self.debug, tmp_dir)
  76. #                for i in self.db.metadata.tables
  77. #                tmp_db.
  78.  
  79.                 tmp_file = os.path.join(tmp_dir, tmp_config.get('file', 'griffith.db', section='database')).encode('utf-8')
  80.                 tmp_metadata = BoundMetaData("sqlite:///%s" % tmp_file)
  81.                 tmp_metadata.tables = self.db.metadata.tables
  82.                 tmp_metadata.create_all()
  83. #                for table in self.db.metadata.tables.keys():
  84.                 for table in [t.name for t in self.db.metadata.table_iterator()]: # table_iterator() will return tables in *correct* order
  85.                     data = self.db.metadata.tables[table].select().execute().fetchall()
  86.                     tmp_metadata.tables[table].insert().execute(data)
  87. #                    for item in data:
  88. #                        tmp_metadata.tables[table].insert().execute(item)
  89.                 tmp_metadata.engine.commit()
  90.                 
  91.                 mzip.write(tmp_file)
  92.                 rmtree(tmp_dir)
  93.             posters_dir = os.path.join(self.locations['posters'])
  94.             for movie in self.db.Movie.select():
  95.                 if movie.image is not None:
  96.                     filename = str(movie.image)+".jpg"
  97.                     filename = os.path.join(posters_dir, filename).encode('utf-8')
  98.                     if os.path.isfile(filename):
  99.                         try:
  100.                             mzip.write(filename)
  101.                         except:
  102.                             self.debug.show("Can't compress %s" % filename)
  103.             mzip.close()
  104.             gutils.info(self, _("Backup has been created"), self.widgets['window'])
  105.  
  106. def restore(self):
  107.     """restores a griffith compressed backup"""
  108.     filename = gutils.file_chooser(_("Restore Griffith backup"), \
  109.         action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons= \
  110.         (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, \
  111.         gtk.STOCK_OPEN, gtk.RESPONSE_OK))
  112.     if filename[0]:
  113.         try:
  114.             zip = zipfile.ZipFile(filename[0], 'r')
  115.         except:
  116.             gutils.error(self, _("Can't read backup file"), self.widgets['window'])
  117.             return False
  118.         mypath = os.path.join(self.locations['posters'])
  119.         old_config_file = False
  120.         for each in zip.namelist():
  121.             file_to_restore = os.path.split(each)
  122.             if not os.path.isdir(file_to_restore[1]):
  123.                 if file_to_restore[1] == '':
  124.                     continue
  125.                 if file_to_restore[1].endswith('.jpg'):
  126.                     myfile = os.path.join(mypath,file_to_restore[1])
  127.                 else:
  128.                     myfile = os.path.join(self.locations['home'],file_to_restore[1])
  129.                 if file_to_restore[1].endswith('.conf'):
  130.                     old_config_file = myfile
  131.                 outfile = open(myfile, 'wb')
  132.                 outfile.write(zip.read(each))
  133.                 outfile.flush()
  134.                 outfile.close()
  135.         zip.close()
  136.  
  137.         # restore config file
  138.         self.config = config.Config(file=os.path.join(self.locations['home'],'griffith.cfg'))
  139.         if old_config_file:
  140.             self.debug.show('Old config file detected. Please note that it will not be used.')
  141.             f = open(old_config_file, 'r')
  142.             old_config_raw_data = f.read()
  143.             f.close()
  144.             if old_config_raw_data.find('griffith.gri') >= -1:
  145.                 self.config.set('file', 'griffith.gri', section='database')
  146.  
  147.         filename = os.path.join(self.locations['home'], self.config.get('name', 'griffith', section='database') + '.db')
  148.  
  149.         self.db.metadata.engine.dispose() # close DB
  150.         from sqlalchemy.orm import clear_mappers
  151.         clear_mappers()
  152.  
  153.         # check if file needs conversion
  154.         if self.config.get('file', 'griffith.db', section='database').lower().endswith('.gri'):
  155.             self.debug.show('Old database format detected. Converting...')
  156.             from dbupgrade import convert_from_old_db
  157.             from initialize    import location_posters
  158.             if convert_from_old_db(self, filename, os.path.join(self.locations['home'], 'griffith.db')):
  159.                 self.config.save()
  160.                 location_posters(self.locations, self.config)
  161.             else:
  162.                 print 'Cant convert old database, exiting.'
  163.                 import sys
  164.                 sys.exit(4)
  165.  
  166.         self.db = sql.GriffithSQL(self.config, self.debug, self.locations['home'])
  167.         from initialize    import dictionaries, people_treeview
  168.         dictionaries(self)
  169.         people_treeview(self)
  170.         # let's refresh the treeview
  171.         self.clear_details()
  172.         self.populate_treeview()
  173.         gutils.info(self, _("Backup restored"), self.widgets['window'])
  174.  
  175. def merge(self):    # FIXME
  176.     """
  177.         Merge database from:
  178.         * compressed backup
  179.         * SQLite2 *.gri file
  180.         * SQLite3 *.db file
  181.     """
  182.     filename = gutils.file_chooser(_("Restore Griffith backup"), \
  183.         action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons= \
  184.         (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, \
  185.         gtk.STOCK_OPEN, gtk.RESPONSE_OK))[0]
  186.     if filename:
  187.         from tempfile import mkdtemp
  188.         from shutil import rmtree, move
  189.  
  190.         #tmp_config={}
  191.         #tmp_config.get('type', 'sqlite', section='database')
  192.  
  193.         if filename.lower().endswith('.zip'):
  194.             tmp_dir = mkdtemp()
  195.             try:
  196.                 zip = zipfile.ZipFile(filename, 'r')
  197.             except:
  198.                 gutils.error(self, _("Can't read backup file"), self.widgets['window'])
  199.                 return False
  200.             for each in zip.namelist():
  201.                 file_to_restore = os.path.split(each)
  202.                 if not os.path.isdir(file_to_restore[1]):
  203.                     myfile = os.path.join(tmp_dir, file_to_restore[1])
  204.                     outfile = open(myfile, 'wb')
  205.                     outfile.write(zip.read(each))
  206.                     outfile.flush()
  207.                     outfile.close()
  208.             # load stored database filename
  209.             tmp_config = config.Config(file=os.path.join(tmp_dir,'griffith.conf'))
  210.             filename = os.path.join(tmp_dir, tmp_config('name', 'griffith', section='database') + '.db')
  211.             zip.close()
  212.  
  213.         # check if file needs conversion
  214.         if filename.lower().endswith(".gri"):
  215.             if os.path.isfile(filename) and  open(filename).readline()[:47] == "** This file contains an SQLite 2.1 database **":
  216.                 self.debug.show("MERGE: SQLite2 database format detected. Converting...")
  217.                 if not self.db.convert_from_sqlite2(filename, os.path.join(tmp_dir, self.config.get('file', 'griffith.db', section='database'))):
  218.                     self.debug.show("MERGE: Can't convert database, aborting.")
  219.                     return False
  220.         tmp_dir, tmp_file = os.path.split(filename)
  221.         self.config.get('file', tmp_file, section='database') 
  222.  
  223.         tmp_db = sql.GriffithSQL(tmp_config, self.debug, tmp_dir)
  224.  
  225.         merged=0
  226.         movies = tmp_db.Movie.count()
  227.         for movie in tmp_db.Movie.select():
  228.             if self.db.Movie.get_by(o_title=movie.o_title) is not None:
  229.                 continue
  230.             t_movies = {}
  231.             for column in movie.mapper.c.keys():
  232.                 t_movies[column] = eval("movie.%s"%column)
  233.  
  234.             # replace number with new one
  235.             t_movies["number"] = gutils.find_next_available(self.db)
  236.  
  237.             # don't restore volume/collection/tag/language/loan data (it's dangerous)
  238.             t_movies.pop('movie_id')
  239.             t_movies.pop('loaned')
  240.             t_movies.pop('volume_id')
  241.             t_movies.pop('collection_id')
  242.  
  243.             if self.db.add_movie(t_movies):
  244.                 print t_movies
  245.  
  246.             if movie.image is not None:
  247.                 dest_file = os.path.join(self.locations['posters'], movie.image+'.jpg')
  248.                 if not os.path.isfile(dest_file):
  249.                     src_file = os.path.join(tmp_dir, movie.image+'.jpg')
  250.                     if os.path.isfile(src_file):
  251.                         move(src_file, dest_file)
  252.             merged+=1
  253.         rmtree(tmp_dir)
  254.  
  255.         from initialize    import dictionaries, people_treeview
  256.         dictionaries(self)
  257.         people_treeview(self)
  258.         # let's refresh the treeview
  259.         self.clear_details()
  260.         self.populate_treeview(self.db.Movie.select())
  261.         #gutils.info(self, _("Databases merged!\n\nProcessed movies: %s\nMerged movies: %s"%(movies, merged)), self.widgets['window'])
  262.  
  263.